#include "GameWnd1.h"
#include <QMessageBox>
#include <QMouseEvent>
#include <QPainter>


GameWnd1::GameWnd1(QWidget *parent) : QFrame(parent)
{
    setMinimumSize((CHESS_COLUMES + 1)*RECT_WIDTH, (CHESS_ROWS + 1)*RECT_HEIGHT);

    mPos = QPoint(-1,-1);
    mBlack = true;

    mClient = new Client;
    connect(mClient, &Client::sigOtherUserMove,this, &GameWnd1::slotOtherUserMove);
    connect(mClient, &Client::sigNewGame,this, &GameWnd1::slotNewGame);

    //转发信号，给MainWindow处理
    connect(mClient, &Client::sigOutput,this, &GameWnd1::sigOutput);
    connect(mClient, &Client::sigUpdateRoomState,this, &GameWnd1::sigUpdateRoomState);
}

GameWnd1::~GameWnd1()
{

}

void GameWnd1::Connect(QString ip, int port, int room)
{
    mClient->ConnectToServer(ip, port, room);
}

void GameWnd1::Say(QString text)
{
    mClient->SendMsg_Say(text);
}

void GameWnd1::Output(QString text)
{
    emit sigOutput(text);
}

void GameWnd1::GetRoomState(QList<ROOM_STATE> &state)
{
    mClient->GetRoomState(state);
}

void GameWnd1::slotNewGame()
{
    mItems.clear();
    mPos = QPoint(-1,-1);
    mBlack = true;
}

void GameWnd1::paintEvent(QPaintEvent *e)
{
    DrawChessboard();
    DrawItems();
    DrawItemWithMouse();

    update();
}

void GameWnd1::DrawChessboard()
{
    QPainter painter(this);


    painter.setPen(QPen(QColor(Qt::black),2));

    for(int i = 0;i<CHESS_COLUMES; i++)
    {
        for (int j = 0; j<CHESS_ROWS; j++)
        {
            painter.drawRect( (i+0.5)*RECT_WIDTH,(j+0.5)*RECT_HEIGHT,RECT_WIDTH,RECT_HEIGHT);
        }
    }
}

void GameWnd1::DrawItems()
{
    QPainter painter(this);
    painter.setPen(QPen(QColor(Qt::transparent)));

    for (int i = 0; i<mItems.size(); i++)
    {
        Item item = mItems[i];
        if(item.mPt == mPos)
        {
            painter.setPen(QPen(QColor("#ff3333"),2,Qt::SolidLine));
            if (item.mBlack)
            {
                painter.setBrush(Qt::black);
            }
            else
            {
                painter.setBrush(Qt::white);
            }
            DrawChessAtPoint(painter,item.mPt);
            painter.setPen(QPen(QColor(Qt::transparent)));
            continue;
        }
        if (item.mBlack)
        {
            painter.setBrush(Qt::black);
        }
        else
        {
            painter.setBrush(Qt::white);
        }
        DrawChessAtPoint(painter,item.mPt);
    }
}

void GameWnd1::DrawChessAtPoint(QPainter& painter,QPoint& pt)
{
    QPoint ptCenter((pt.x()+0.5)*RECT_WIDTH,(pt.y()+0.5)*RECT_HEIGHT);
    painter.drawEllipse(ptCenter,RECT_WIDTH / 2,RECT_HEIGHT / 2);
}

void GameWnd1::DrawItemWithMouse()
{
    QPainter painter(this);
    painter.setPen(QPen(QColor(Qt::transparent)));

    if (mClient->IsBlack())
    {
        painter.setBrush(Qt::black);
    }
    else
    {
        painter.setBrush(Qt::white);
    }

    painter.drawEllipse(mapFromGlobal(QCursor::pos()),RECT_WIDTH / 2,RECT_HEIGHT / 2);

}

void GameWnd1::mousePressEvent(QMouseEvent * e)
{
    if(flag==0)
    {
    if (mClient->IsBlack())
    {
        if (!mBlack)
        {
            return;
        }
    }
    else
    {
        if (mBlack)
        {
            return;
        }
    }

    QPoint pt;
    pt.setX( (e->pos().x() ) / RECT_WIDTH);
    pt.setY( (e->pos().y() ) / RECT_HEIGHT);

    for (int i = 0; i<mItems.size(); i++)
    {
        Item item = mItems[i];
        if (item.mPt == pt)
        {
            //已有棋子
            return;
        }
    }
    mPos = pt;
    mClient->SendMsg_Move(pt.x(),pt.y());

    Item item(pt,mBlack);
    mItems.append(item);

    int nLeft =			CountNearItem(item,QPoint(-1,0));
    int nLeftUp =		CountNearItem(item,QPoint(-1,-1));
    int nUp =			CountNearItem(item,QPoint(0,-1));
    int nRightUp =		CountNearItem(item,QPoint(1,-1));
    int nRight =		CountNearItem(item,QPoint(1,0));
    int nRightDown =	CountNearItem(item,QPoint(1,1));
    int nDown =			CountNearItem(item,QPoint(0,1));
    int nLeftDown =		CountNearItem(item,QPoint(-1,1));
    if ( (nLeft + nRight) >= 4 ||
         (nLeftUp + nRightDown) >= 4 ||
         (nUp + nDown) >= 4 ||
         (nRightUp + nLeftDown) >= 4 )
    {
        if (mBlack == mClient->IsBlack())
        {
            //赢的一方通知服务器自己赢了
            mClient->SendMsg_Success();
        }

        QString str = mBlack? QStringLiteral("黑棋胜利！") : QStringLiteral("白棋胜利！");
        QMessageBox::information(this, QStringLiteral("游戏结束"),str, QMessageBox::Yes , QMessageBox::Yes);
        mItems.clear();
        //NewGame();
        return;
    }
    mBlack = !mBlack;
}
}
void GameWnd1::AIPressEvent(QMouseEvent * e)
{
    if (mClient->IsBlack())
    {
        if (!mBlack)
        {
            return;
        }
    }
    else
    {
        if (mBlack)
        {
            return;
        }
    }

    QPoint pt;
    pt.setX( (e->pos().x() ) / RECT_WIDTH);
    pt.setY( (e->pos().y() ) / RECT_HEIGHT);

    for (int i = 0; i<mItems.size(); i++)
    {
        Item item = mItems[i];
        if (item.mPt == pt)
        {
            //已有棋子
            return;
        }
    }
    mPos = pt;
    mClient->SendMsg_Move(pt.x(),pt.y());

    Item item(pt,mBlack);
    mItems.append(item);

    int nLeft =			CountNearItem(item,QPoint(-1,0));
    int nLeftUp =		CountNearItem(item,QPoint(-1,-1));
    int nUp =			CountNearItem(item,QPoint(0,-1));
    int nRightUp =		CountNearItem(item,QPoint(1,-1));
    int nRight =		CountNearItem(item,QPoint(1,0));
    int nRightDown =	CountNearItem(item,QPoint(1,1));
    int nDown =			CountNearItem(item,QPoint(0,1));
    int nLeftDown =		CountNearItem(item,QPoint(-1,1));
    if ( (nLeft + nRight) >= 4 ||
         (nLeftUp + nRightDown) >= 4 ||
         (nUp + nDown) >= 4 ||
         (nRightUp + nLeftDown) >= 4 )
    {
        if (mBlack == mClient->IsBlack())
        {
            //赢的一方通知服务器自己赢了
            mClient->SendMsg_Success();
        }

        QString str = mBlack? QStringLiteral("黑棋胜利！") : QStringLiteral("白棋胜利！");
        QMessageBox::information(this, QStringLiteral("游戏结束"),str, QMessageBox::Yes , QMessageBox::Yes);
        mItems.clear();
        //NewGame();
        return;
    }
    mBlack = !mBlack;
}
int GameWnd1::CountNearItem(Item item,QPoint ptDirection)
{
    int nCount = 0;
    item.mPt += ptDirection;

    while (mItems.contains(item))
    {
        nCount++;
        item.mPt += ptDirection;
    }
    return nCount;
}

void GameWnd1::slotOtherUserMove( int x,int y )
{
    mPos = QPoint(x,y);

    QPoint pt(x,y);
    Item item(pt,mBlack);
    mItems.append(item);

    int nLeft =			CountNearItem(item,QPoint(-1,0));
    int nLeftUp =		CountNearItem(item,QPoint(-1,-1));
    int nUp =			CountNearItem(item,QPoint(0,-1));
    int nRightUp =		CountNearItem(item,QPoint(1,-1));
    int nRight =		CountNearItem(item,QPoint(1,0));
    int nRightDown =	CountNearItem(item,QPoint(1,1));
    int nDown =			CountNearItem(item,QPoint(0,1));
    int nLeftDown =		CountNearItem(item,QPoint(-1,1));
    if ( (nLeft + nRight) >= 4 ||
        (nLeftUp + nRightDown) >= 4 ||
        (nUp + nDown) >= 4 ||
        (nRightUp + nLeftDown) >= 4 )
    {
        QString str = mBlack? QStringLiteral("黑棋胜利！") : QStringLiteral("白棋胜利！");
        QMessageBox::information(NULL, QStringLiteral("游戏结束"),str, QMessageBox::Yes , QMessageBox::Yes);

        mItems.clear();
        //NewGame();
        return;
    }


    mBlack = !mBlack;
    update();
}
//计算每格分数函数
void GameWnd1::calculateScore(){
    //统计玩家或者电脑连成的子
    int personNum = 0; //玩家连成子的个數
    int botNum = 0;   //AI连成子的个數
    int emptyNum = 0;   //各方向空白位的个數

    //清空评分数组
    scoreMapVec.clear();
    for(int i=0;i<Tsize;i++){
        std::vector<int> lineScores;
        for(int j=0;j<Tsize;j++){
            lineScores.push_back(0);
        }
        scoreMapVec.push_back(lineScores);
    }
    //计分
    /*计分个人理解：
     * 遍历每一个格子，判断哪些是空白的点(即为0的点)，以该点为中心，判断周围的八个点向外延伸的四格，
     * 有多少个是黑子、白子、空白，以此作为依据来评分。下方算法是以守为主，所以守的分数>攻的分数
     */
    for(int row=0;row<Tsize;row++){
        for(int col=0;col<Tsize;col++){
            //空白点才算
            if(row>0 && col>0 && gameMapVec[row][col]==0){
                //遍历周围8个方向
                for(int y=-1;y<=1;y++){
                    for(int x=-1;x<=1;x++){
                        //重置
                        personNum = 0;
                        botNum = 0;
                        emptyNum = 0;
                        //原坐标不算
                        if(!(y==0 && x==0)){
                            //每个方向延伸4个子

                            //对玩家黑子評分(正反两个方向)
                            for(int i=1;i<=4;i++){
                                if(row+i*y>0 && row+i*y<Tsize &&
                                   col+i*x>0 && col+i*x<Tsize &&
                                   gameMapVec[row+i*y][col+i*x]==1){ //真人玩家的子
                                    personNum++;
                                }else if(row+i*y>0 && row+i*y<Tsize &&
                                         col+i*x>0 && col+i*x<Tsize &&
                                         gameMapVec[row+i*y][col+i*x]==0){ //空白位
                                    emptyNum++;
                                    break;
                                }else{ //出边界，或有白子
                                    break;
                                }
                            }
                            for(int i=1;i<=4;i++){
                                if(row-i*y>0 && row-i*y<Tsize &&
                                   col-i*x>0 && col-i*x<Tsize &&
                                   gameMapVec[row-i*y][col-i*x]==1){ //真人玩家的子
                                    personNum++;
                                }else if(row-i*y>0 && row-i*y<Tsize &&
                                         col-i*x>0 && col-i*x<Tsize &&
                                         gameMapVec[row-i*y][col-i*x]==0){ //空白位
                                    emptyNum++;
                                    break;
                                }else{ //出边界，或有白子
                                    break;
                                }
                            }
                            if(personNum == 1){                 //殺2
                                scoreMapVec[row][col]+=10;
                            }else if(personNum == 2){           //殺3
                                if(emptyNum == 1)
                                    scoreMapVec[row][col]+=30;
                                else if(emptyNum == 2)
                                    scoreMapVec[row][col]+=40;
                            }else if(personNum == 3){           //殺4
                                //量与空位不一样，优先级不同
                                if(emptyNum == 1)
                                    scoreMapVec[row][col]+=60;
                                else if(emptyNum == 2)
                                    scoreMapVec[row][col]+=110;
                            }else if(personNum == 4){           //殺5
                                scoreMapVec[row][col]+=10100;
                            }

                            //进行一次清空
                            emptyNum = 0;

                            //对AI白子評分
                            for(int i=1;i<=4;i++){
                                if(row+i*y>0 && row+i*y<Tsize &&
                                   col+i*x>0 && col+i*x<Tsize &&
                                   gameMapVec[row+i*y][col+i*x]==-1){ //AI的子
                                    botNum++;
                                }else if(row+i*y>0 && row+i*y<Tsize &&
                                         col+i*x>0 && col+i*x<Tsize &&
                                         gameMapVec[row+i*y][col+i*x]==0){ //空白位
                                    emptyNum++;
                                    break;
                                }else{ //出边界
                                    break;
                                }
                            }
                            for(int i=1;i<=4;i++){
                                if(row-i*y>0 && row-i*y<Tsize &&
                                   col-i*x>0 && col-i*x<Tsize &&
                                   gameMapVec[row-i*y][col-i*x]==-1){ //AI的子
                                    botNum++;
                                }else if(row-i*y>0 && row-i*y<Tsize &&
                                         col-i*x>0 && col-i*x<Tsize &&
                                         gameMapVec[row-i*y][col-i*x]==0){ //空白位
                                    emptyNum++;
                                    break;
                                }else{ //出边界
                                    break;
                                }
                            }
                            if(botNum == 0){
                                scoreMapVec[row][col]+=5;  //活1
                            }else if(botNum == 1){
                                scoreMapVec[row][col]+=10; //活2
                            }else if(botNum == 2){         //活3
                                if(emptyNum == 1)
                                    scoreMapVec[row][col]+=25;
                                else if(emptyNum == 2)
                                    scoreMapVec[row][col]+=50;
                            }else if(botNum == 3){         //活4
                                if(emptyNum == 1)
                                    scoreMapVec[row][col]+=55;
                                else if(emptyNum == 2)
                                    scoreMapVec[row][col]+=100;
                            }else if(botNum >= 4){         //活5
                                scoreMapVec[row][col]+=20000;
                            }


                        }
                    }
                }
            }
        }
    }

}
//AI执行下棋
void GameWnd1::actionByAI(int &clickRow,int &clickCol){
    if(flag==1)
    {//计算评分
    calculateScore();

    //从评分中找出最大分数的位置
    int maxScore = 0;
    std::vector<std::pair<int,int>> maxPoints;
    for(int row = 1;row<Tsize;row++){
        for(int col = 1;col<Tsize;col++){
            //前提是这个坐标是空的

            if(gameMapVec[row][col] == 0){
                if(scoreMapVec[row][col]>maxScore){     //找最大数和坐标
                    maxPoints.clear();
                    maxScore = scoreMapVec[row][col];
                    maxPoints.push_back(std::make_pair(row,col));

                }else if(scoreMapVec[row][col] == maxScore){   //如果有多个最大值就将他们储存起來，在后面的代码随机抽一个
                    maxPoints.push_back(std::make_pair(row,col));
                }
            }
        }
    }
    //随即落点，如果有多个点
    srand((unsigned)time(0));
    int index = rand()%maxPoints.size();
    std::pair<int,int> pointPair = maxPoints.at(index);

    clickRow = pointPair.first;
    clickCol = pointPair.second;
    QPoint pt;
    pt.setX(clickRow);
    pt.setY(clickCol);

    for (int i = 0; i<mItems.size(); i++)
    {
        Item item = mItems[i];
        if (item.mPt == pt)
        {
            //已有棋子
            return;
        }
    }
    mPos = pt;
    mClient->SendMsg_Move(pt.x(),pt.y());

    Item item(pt,mBlack);
    mItems.append(item);

    int nLeft =			CountNearItem(item,QPoint(-1,0));
    int nLeftUp =		CountNearItem(item,QPoint(-1,-1));
    int nUp =			CountNearItem(item,QPoint(0,-1));
    int nRightUp =		CountNearItem(item,QPoint(1,-1));
    int nRight =		CountNearItem(item,QPoint(1,0));
    int nRightDown =	CountNearItem(item,QPoint(1,1));
    int nDown =			CountNearItem(item,QPoint(0,1));
    int nLeftDown =		CountNearItem(item,QPoint(-1,1));
    if ( (nLeft + nRight) >= 4 ||
         (nLeftUp + nRightDown) >= 4 ||
         (nUp + nDown) >= 4 ||
         (nRightUp + nLeftDown) >= 4 )
    {
        if (mBlack == mClient->IsBlack())
        {
            //赢的一方通知服务器自己赢了
            mClient->SendMsg_Success();
        }

        QString str = mBlack? QStringLiteral("黑棋胜利！") : QStringLiteral("白棋胜利！");
        QMessageBox::information(this, QStringLiteral("游戏结束"),str, QMessageBox::Yes , QMessageBox::Yes);
        mItems.clear();
        //NewGame();
        return;
    }
    mBlack = !mBlack;
}
}
